package com.wholeintech.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;  
import javax.xml.parsers.DocumentBuilderFactory;  
import javax.xml.parsers.ParserConfigurationException;  

  
import org.w3c.dom.Document;  
import org.w3c.dom.Element; 
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;   
import org.xml.sax.SAXException;

import android.util.Log;

import com.wholeintech.entity.BoxInfo;
import com.wholeintech.entity.KnxDevice;
import com.wholeintech.entity.ProjectInfo;
import com.wholeintech.entity.ServiceInfo;
import com.wholeintech.entity.Scene;
import com.wholeintech.entity.SceneDevice;
import com.wholeintech.entity.Navigation;
import com.wholeintech.entity.DeviceDb;

public class HcpFile {
	public final static String TAG = "HcpFile";
	public final static String DEFAULT_HCP_PATH       = "/sdcard/project.hcp";
	public final static String BOSCH_HCP_PATH       = "/sdcard/project1.hcp";
	public final static String DEFAULT_HCP_DST_FOLDER = "/sdcard/";
	
	public final static String DEFAULT_HCP_PROJECT_INFO_PATH = "/sdcard/project_info.xml";
	public final static String DEFAULT_HCP_PATH_FMT = "/sdcard/box%d.xml";
	
	public final static int INVALID_CMD_INT = -1;
	public final static int INVALID_COLOR   = 0xFEFEFEFE;
	
    public ProjectInfo projInfo = new ProjectInfo();
    public BoxInfo boxInfo = new BoxInfo();
    public List<DeviceDb> devices = new ArrayList<DeviceDb>();
    public List<KnxDevice> knxDevices = new ArrayList<KnxDevice>();
    public List<Scene> scenes = new ArrayList<Scene>();
    public List<SceneDevice> sceneDevs = new ArrayList<SceneDevice>();
    public List<Navigation> navis = new ArrayList<Navigation>();
    public List<ServiceInfo> services = new ArrayList<ServiceInfo>();
    
    
    public void parser(String filename){
    	Log.d(TAG, "start hcp parser");
    	if(filename == null)
    		filename = DEFAULT_HCP_PATH;
    	Zip.Ectract(filename, DEFAULT_HCP_DST_FOLDER);
    	
    	parserProject();
    	parserBox();
    }

	public void parser(int fileValue){

		String fileName = new String(DEFAULT_HCP_PATH);
		if(fileValue != 0)
		{
			fileName = BOSCH_HCP_PATH;
		}
		Zip.Ectract(fileName, DEFAULT_HCP_DST_FOLDER);
		Log.d(TAG, "start hcp parser :"+ fileName);
		parserProject();
		parserBox();
	}

    public String getItemText(NodeList list, String key, String defaultValue){
    	if(list == null || list.getLength() < 1)
    		return defaultValue;
    	Element node = (Element)list.item(0);
    	return getItemText(node, key, defaultValue);
    }
 
    public String getItemText(Element node, String key, String defaultValue){
    	if(node == null)
    		return defaultValue;

    	NodeList list2 = node.getElementsByTagName(key);
    	if(list2 == null || list2.getLength() < 1)
    		return defaultValue;    	

    	Element node2 = (Element)list2.item(0);
    	Node n = node2.getFirstChild();
    	if(n == null)
    		return defaultValue;
    	
    	String s = n.getNodeValue();
    	if(s != null)
    		return s;
    	return defaultValue;
    }
    
    public int getItemInt(NodeList list, String key, int defaultValue){
    	String s = getItemText(list, key, null);
    	if(s == null)
    		return defaultValue;
    	return Integer.valueOf(s);
    }
    
    public int getItemInt(Element node, String key, int defaultValue){
    	String s = getItemText(node, key, null);
    	if(s == null)
    		return defaultValue;
    	return Integer.valueOf(s);
    }

    public int getItemIntHex(NodeList list, String key, int defaultValue){
    	String s = getItemText(list, key, null);
    	if(s == null)
    		return defaultValue;
    	return Integer.parseInt(s, 16);
    }
    
    public int getItemIntHex(Element node, String key, int defaultValue){
    	String s = getItemText(node, key, null);
    	if(s == null)
    		return defaultValue;
    	return Integer.parseInt(s, 16);
    }
    
    //"/sdcard/project_info.xml"    
    public void parserProject() {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc = null;
        try {  
            DocumentBuilder builder = dbf.newDocumentBuilder();  
            InputStream in = new FileInputStream(DEFAULT_HCP_PROJECT_INFO_PATH);  
            doc = builder.parse(in);  
        } catch (ParserConfigurationException e) {  
            e.printStackTrace();  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (SAXException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } 
        
        if(doc == null)
        	return;
        
        // root <university>   
        Element project = doc.getDocumentElement();  
        if (project == null) 
        {
        	Log.d(TAG, "root Element not found.");
        	return;  
        }
        Log.d(TAG, "XML root:" + project.getNodeName());

    	String s;
    	s = getItemText(project, "name", "");
    	projInfo.setName(s);
    	s = getItemText(project, "country", null);
    	projInfo.setCountry(s);
    	s = getItemText(project, "province", null);
    	projInfo.setProvince(s);
    	s = getItemText(project, "city", null);
    	projInfo.setCity(s);             
    	s = getItemText(project, "district", null);
    	projInfo.setDistrict(s);       
    	s = getItemText(project, "address", null);
    	projInfo.setAddress(s);       
    	s = getItemText(project, "house_id", null);
    	projInfo.setHouseId(s); 
    	s = getItemText(project, "room", null);
    	projInfo.setRoom(s); 
    	projInfo.setIndex(getItemInt(project, "box_index", 0));
    	
    	Log.e(TAG, "------------------------------------------");
    	Log.e(TAG, "proj_info:" + projInfo.toString());
    }

    //"/sdcard/box0.xml"
    public void parserBox(){
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document doc = null;
        try {  
            DocumentBuilder builder = dbf.newDocumentBuilder();
            //build box0~31.xml path
            String boxXmlPath = String.format(DEFAULT_HCP_PATH_FMT, projInfo.getIndex());
            Log.d(TAG, "Selected box xml path:" + boxXmlPath);
            InputStream in = new FileInputStream(boxXmlPath);  
            doc = builder.parse(in);  
        } catch (ParserConfigurationException e) {  
            e.printStackTrace();  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (SAXException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } 
        
        if(doc == null)
        	return;
        
        // root <university>   
        Element box = doc.getDocumentElement();  
        if (box == null) 
        {
        	Log.d(TAG, "root Element not found.");
        	return;  
        }
        Log.d(TAG, "XML root:" + box.getNodeName());
        
        parserBoxInfo(box);
        parserDevice(box);
        parserKnxDevice(box);
        parserScene(box);
        parserNavi(box);
        parserService(box);
    }
    
    public void parserBoxInfo(Element box) {
    	NodeList box_info = box.getElementsByTagName("box_info");
    	box.getChildNodes();
    	if(box_info == null || box_info.getLength() <= 0)
    		return;
    	
    	String s;
    	s = getItemText(box_info, "name", "");
    	boxInfo.setName(s);
    	s = getItemText(box_info, "box_id", null);
    	boxInfo.setBoxId(s);
    	s = getItemText(box_info, "mac_addr", null);
    	boxInfo.setMacAddr(s);
    	s = getItemText(box_info, "zkey", null);
    	boxInfo.setZkey(s);
    	
    	s=String.format("%s,%s",projInfo.getHouseId(),System.currentTimeMillis());
    	boxInfo.setHouseId(s);
    	
    	boxInfo.setRegionId(getItemInt(box_info, "region_id", 0));
    	
    	Log.e(TAG, "------------------------------------------");
    	Log.e(TAG, "box_info:" + boxInfo.toString());
    }
    
    public void parserDevice(Element box) {
    	NodeList device_list = box.getElementsByTagName("device_list");
    	if(device_list == null || device_list.getLength() < 1)
    		return;
    	Element ele = (Element)device_list.item(0);
    	NodeList device = ele.getElementsByTagName("device");
    	if(device == null || device.getLength() < 1)
    		return;
    	
    	Log.e(TAG, "------------------------------------------");
    	for(int i = 0; i < device.getLength(); i++)
    	{
    		Element eleDev = (Element)device.item(i);
	    	DeviceDb dev = new DeviceDb();
	    	dev.setBoxId(boxInfo.getBoxId());
	    	dev.setName(getItemText(eleDev, "name", ""));
	    	dev.setDevId(getItemText(eleDev, "dev_id", ""));
	    	dev.setGwDevId(getItemText(eleDev, "gw_dev_id", ""));
	    	dev.setMacAddr(getItemText(eleDev, "mac_addr", ""));
	    	dev.setBindSw1(getItemText(eleDev, "bind1", ""));
	    	dev.setBindSw2(getItemText(eleDev, "bind2", ""));
	    	dev.setType(getItemInt(eleDev, "type", 0));
	    	dev.setNetType(getItemInt(eleDev, "net_type", 1));    // 1 for zigbee
	    	//dev.setVisible(getItemInt(eDev, "visible", 1));   	//1 for visible
	    	dev.setRegionId(getItemInt(eleDev, "region_id", 0));
	    	dev.setDevCfg(getItemText(eleDev, "dev_cfg", ""));
	    	 
	    	devices.add(dev);
	    	Log.e(TAG, "add Device:" + dev.toStringSimple());
    	}
    }
/*
#define KNX_PATH_NAME_SW_OPEN         ("sw_open")
#define KNX_PATH_NAME_SW_CLOSE        ("sw_close")
#define KNX_PATH_NAME_SW_UP           ("sw_up")
#define KNX_PATH_NAME_SW_DOWN         ("sw_down")
#define KNX_PATH_NAME_SW_STOP         ("sw_stop")
#define KNX_PATH_NAME_SW_FB           ("sw_fb")
#define KNX_PATH_NAME_BRIGHTNESS      ("brightness")
#define KNX_PATH_NAME_BRIGHTNESS_FB   ("brightness_fb")
#define KNX_PATH_NAME_TEMPE           ("tempe")
#define KNX_PATH_NAME_TEMPE_FB        ("tempe_fb")
#define KNX_PATH_NAME_WIND_AUTO       ("wind_auto")
#define KNX_PATH_NAME_WIND_MANUAL     ("wind_manual")
#define KNX_PATH_NAME_WIND0           ("wind0")
#define KNX_PATH_NAME_WIND1           ("wind1")
#define KNX_PATH_NAME_WIND2           ("wind2")
#define KNX_PATH_NAME_WIND3           ("wind3")
#define KNX_PATH_NAME_WIND4           ("wind4")
#define KNX_PATH_NAME_WIND5           ("wind5")
#define KNX_PATH_NAME_WIND6           ("wind6")
#define KNX_PATH_NAME_WIND7           ("wind7")
#define KNX_PATH_NAME_WIND_FB         ("wind_fb")
#define KNX_PATH_NAME_MODE0           ("mode0")
#define KNX_PATH_NAME_MODE1           ("mode1")
#define KNX_PATH_NAME_MODE2           ("mode2")
#define KNX_PATH_NAME_MODE3           ("mode3")
#define KNX_PATH_NAME_MODE4           ("mode4")
#define KNX_PATH_NAME_MODE5           ("mode5")
#define KNX_PATH_NAME_MODE6           ("mode6")
#define KNX_PATH_NAME_MODE7           ("mode7")
#define KNX_PATH_NAME_MODE_FB         ("mode_fb")
 */
    public void parserKnxDevice(Element box) {
    	NodeList knx_device_list = box.getElementsByTagName("knx_device_list");
    	if(knx_device_list == null || knx_device_list.getLength() < 1)
    		return;
    	Element ele = (Element)knx_device_list.item(0);
    	NodeList device = ele.getElementsByTagName("knx_device");
    	if(device == null || device.getLength() < 1)
    		return;
    	
    	Log.e(TAG, "------------------------------------------");
    	for(int i = 0; i < device.getLength(); i++)
    	{
    		Element eleDev = (Element)device.item(i);
	    	KnxDevice dev = new KnxDevice();
	    	dev.setDevId(getItemText(eleDev, "dev_id", ""));
	    	dev.setSwOpen(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_open", "")));
	    	dev.setSwClose(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_close", "")));
	    	dev.setSwUp(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_up", "")));
	    	dev.setSwDown(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_down", "")));
	    	dev.setSwStop(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_stop", "")));
	    	dev.setSwFb(KnxDevice.parserPathCmd(getItemText(eleDev, "sw_fb", "")));
	    	dev.setBrightness(KnxDevice.parserPathCmd(getItemText(eleDev, "brightness", "")));
	    	dev.setBrightnessFb(KnxDevice.parserPathCmd(getItemText(eleDev, "brightness_fb", "")));
	    	dev.setTempe(KnxDevice.parserPathCmd(getItemText(eleDev, "tempe", "")));
	    	dev.setTempeFb(KnxDevice.parserPathCmd(getItemText(eleDev, "tempe_fb", "")));
	    	
	    	dev.setWindAuto(KnxDevice.parserPathCmd(getItemText(eleDev, "wind_auto", "")));
	    	dev.setWindManual(KnxDevice.parserPathCmd(getItemText(eleDev, "wind_manual", "")));
	    	dev.setWind0(KnxDevice.parserPathCmd(getItemText(eleDev, "wind0", "")));
	    	dev.setWind1(KnxDevice.parserPathCmd(getItemText(eleDev, "wind1", "")));
	    	dev.setWind2(KnxDevice.parserPathCmd(getItemText(eleDev, "wind2", "")));
	    	dev.setWind3(KnxDevice.parserPathCmd(getItemText(eleDev, "wind3", "")));
	    	dev.setWind4(KnxDevice.parserPathCmd(getItemText(eleDev, "wind4", "")));
	    	dev.setWind5(KnxDevice.parserPathCmd(getItemText(eleDev, "wind5", "")));
	    	dev.setWind6(KnxDevice.parserPathCmd(getItemText(eleDev, "wind6", "")));
	    	dev.setWind7(KnxDevice.parserPathCmd(getItemText(eleDev, "wind7", "")));
	    	dev.setWindFb(KnxDevice.parserPathCmd(getItemText(eleDev, "wind_fb", "")));
	    	
	    	dev.setMode0(KnxDevice.parserPathCmd(getItemText(eleDev, "mode0", "")));
	    	dev.setMode1(KnxDevice.parserPathCmd(getItemText(eleDev, "mode1", "")));
	    	dev.setMode2(KnxDevice.parserPathCmd(getItemText(eleDev, "mode2", "")));
	    	dev.setMode3(KnxDevice.parserPathCmd(getItemText(eleDev, "mode3", "")));
	    	dev.setMode4(KnxDevice.parserPathCmd(getItemText(eleDev, "mode4", "")));
	    	dev.setMode5(KnxDevice.parserPathCmd(getItemText(eleDev, "mode5", "")));
	    	dev.setMode6(KnxDevice.parserPathCmd(getItemText(eleDev, "mode6", "")));
	    	dev.setMode7(KnxDevice.parserPathCmd(getItemText(eleDev, "mode7", "")));
	    	dev.setModeFb(KnxDevice.parserPathCmd(getItemText(eleDev, "mode_fb", "")));
	    	
	    	knxDevices.add(dev);
	    	Log.e(TAG, "add KnxDevice:\n");
	    	dev.dump();
    	}
    }
    
    public void parserScene(Element box) {
    	NodeList scene_list = box.getElementsByTagName("scene_list");
    	if(scene_list == null || scene_list.getLength() < 1)
    		return;
    	Element ele = (Element)scene_list.item(0);
    	NodeList scene = ele.getElementsByTagName("scene");
    	if(scene == null || scene.getLength() < 1)
    		return;
    	
    	for(int i = 0; i < scene.getLength(); i++)
    	{
        	Log.e(TAG, "------------------------------------------");
        	int visible;
        	String sceneId; // = "sceneId" + i;  //FIXME: Raymanfeng SceneId = "sceneId0" ~ "sceneId31"
    		
    		Element eleScene = (Element)scene.item(i);
    		Scene scn = new Scene();
    		scn.setSceneName(getItemText(eleScene, "name", ""));
    		sceneId = getItemText(eleScene, "scene_id", "");
    		visible = getItemInt(eleScene, "visible", 1);
    		scn.setSceneId(sceneId);
    		scn.setBoxId(boxInfo.getBoxId());
    		scn.setVisible(visible);
	    	scenes.add(scn);
	    	Log.e(TAG, "add Scene:" + scn.toString());
	    	
	    	NodeList setting = eleScene.getElementsByTagName("setting");
	    	if(setting == null || setting.getLength() < 1)
	    		continue;
	    	
	    	Element eleSetting = (Element)setting.item(0);
	    	NodeList device = eleSetting.getElementsByTagName("device");
	    	for(int j = 0; j < device.getLength(); j++)
	    	{
	    		Element eleDev = (Element)device.item(j);
	    		SceneDevice scnDev = new SceneDevice();
	    		scnDev.setSceneId(sceneId);
	    		scnDev.setDevId(getItemText(eleDev, "dev_id", ""));
	    		
	    		scnDev.setSw(getItemInt(eleDev, "sw", INVALID_CMD_INT));
	    		scnDev.setBrightness(getItemInt(eleDev, "brightness", INVALID_CMD_INT));
	    		scnDev.setMode(getItemInt(eleDev, "mode", INVALID_CMD_INT));
	    		scnDev.setWind(getItemInt(eleDev, "wind", INVALID_CMD_INT));
	    		scnDev.setTemperature(getItemInt(eleDev, "temperature", INVALID_CMD_INT));
	    		scnDev.setRunstate(getItemInt(eleDev, "runstate", INVALID_CMD_INT));
	    		
	    		scnDev.setColor(getItemIntHex(eleDev, "color", INVALID_COLOR));

	    		sceneDevs.add(scnDev);
		    	Log.e(TAG, "add SceneDevice:\n    " + scnDev.toString());
	    	}
    	}
    }

    public void parserNavi(Element box) {
    	NodeList nav_list = box.getElementsByTagName("nav_list");
    	if(nav_list == null || nav_list.getLength() < 1)
    		return;
    	
    	Element ele = (Element)nav_list.item(0);
    	NodeList item = ele.getElementsByTagName("item");
    	if(item == null || item.getLength() < 1)
    		return;
  
	    Log.e(TAG, "------------------------------------------");
    	for(int i = 0; i < item.getLength(); i++)
    	{
    		Element eleNav = (Element)item.item(i);
    		Navigation nav = new Navigation();
    		nav.setName(getItemText(eleNav, "name", ""));
    		nav.setDevId(getItemText(eleNav, "dev_id", ""));
    		nav.setAnchor(getItemText(eleNav, "anchor", ""));
	    	
    		nav.setType(getItemInt(eleNav, "type", 0));
	    	
	    	navis.add(nav);
	    	Log.e(TAG, "add Navigation:" + nav.toString());
    	}	
    }

    public void parserService(Element box) {
    	NodeList sevice_list = box.getElementsByTagName("sevice_list");
    	if(sevice_list == null || sevice_list.getLength() < 1)
    		return;
    	Element ele = (Element)sevice_list.item(0);
    	NodeList sevice = ele.getElementsByTagName("sevice");
    	if(sevice == null || sevice.getLength() < 1)
    		return;
  
	    Log.e(TAG, "------------------------------------------");
    	for(int i = 0; i < sevice.getLength(); i++)
    	{
    		Element eleServ = (Element)sevice.item(i);
    		ServiceInfo serv = new ServiceInfo();
    		serv.setName(getItemText(eleServ, "name", ""));
    		serv.setPhone(getItemText(eleServ, "phone", ""));

    		services.add(serv);
	    	Log.e(TAG, "add ServiceInfo:" + serv.toString());
    	}
    }
    
}
